package com.aoxiang.zbox.service.impl;

import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONObject;
import com.aoxiang.zbox.common.DataSourceContextHolder;
import com.aoxiang.zbox.common.UserContextHolder;
import com.aoxiang.zbox.common.exception.BaseException;
import com.aoxiang.zbox.common.exception.ErrorCodeEnum;
import com.aoxiang.zbox.common.util.JwtUtil;
import com.aoxiang.zbox.common.util.UserDatabaseUtil;
import com.aoxiang.zbox.config.DataSourceConfig;
import com.aoxiang.zbox.mapper.UserMapper;
import com.aoxiang.zbox.model.dto.LoginUser;
import com.aoxiang.zbox.model.dto.RegisterUser;
import com.aoxiang.zbox.model.dto.SimpleUser;
import com.aoxiang.zbox.model.entity.User;
import com.aoxiang.zbox.model.vo.LoginUserVO;
import com.aoxiang.zbox.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * Description:
 *
 * @author: aoxiang
 * @create: 2025-03-29 10:50
 **/

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public void writeOff() {
        Long id = UserContextHolder.getUser().getId();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, id);
        userMapper.delete(queryWrapper);

        String userDatabasePath = DataSourceConfig.getUserDatabasePath(id);
        UserDatabaseUtil.deleteUserDatabase(userDatabasePath);
    }

    @Override
    public void logout(String authorization) {
        JSONObject jsonObject = jwtUtil.getJsonObject(authorization);
        if (jsonObject == null || !jsonObject.containsKey("userId")) {
            throw new BaseException(ErrorCodeEnum.TOKEN_EXPIRED);
        }
        String userIdStr = String.valueOf(jsonObject.get("userId"));
        Long userId = Long.parseLong(userIdStr);
        deleteToken(userId);
        UserContextHolder.userClear();
        DataSourceContextHolder.setDataSource(DataSourceConfig.BASE_DATASOURCE_KEY);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginUserVO login(LoginUser user) {
        User userInDb = findUserByAccount(user.getAccount());
        if (userInDb == null || !BCrypt.checkpw(user.getPassword(), userInDb.getPassword())) {
            LOGGER.info("账号或密码错误: {}", user);
            throw new BaseException(ErrorCodeEnum.USER_PASSWORD_ERROR);
        }
        String token = jwtUtil.createToken(userInDb.getId(), userInDb.getUsername());
        updateToken(userInDb.getId(), token);
        UserContextHolder.setUser(new SimpleUser(userInDb.getId(), userInDb.getUsername()));

        // 封装响应
        LoginUserVO loginUserVO = new LoginUserVO();
        loginUserVO.setToken(token);
        loginUserVO.setUser(new LoginUserVO.BaseUser(userInDb.getId(), userInDb.getUsername(), userInDb.getAccount()));

        UserDatabaseUtil.createUserDatabase(userInDb.getId());
        return loginUserVO;
    }

    private void updateToken(Long userId, String token) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getToken, token)
                .set(User::getUpdatedAt, LocalDateTime.now())
                .eq(User::getId, userId);
        userMapper.update(null, updateWrapper);
    }

    private void deleteToken(Long userId) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getToken, null)
                .set(User::getUpdatedAt, LocalDateTime.now())
                .eq(User::getId, userId);
        userMapper.update(null, updateWrapper);
    }

    private User findUserByAccount(String account) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, account);
        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public Long register(RegisterUser registerUser) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, registerUser.getAccount());
        if (userMapper.exists(queryWrapper)) {
            throw new BaseException(ErrorCodeEnum.USERNAME_EXISTS);
        }
        User user = new User();
        user.setAccount(registerUser.getAccount());
        user.setPassword(BCrypt.hashpw(registerUser.getPassword()));
        user.setUsername(registerUser.getUsername());
        userMapper.insert(user);

        UserDatabaseUtil.createUserDatabase(user.getId());
        return user.getId();
    }
}
